package server;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileTransfer {

    int totalNrOfFrames = 0;
    ArrayList<Socket> toSockets = new ArrayList<>();
    ArrayList<Socket> fromSockets = new ArrayList<>();
    Socket fromCommunicationSocket;
    Socket toCommunicationSocket;
    int nrOfSockets = -1;
    int frameSize = 0;
    long fileSize = 0;
    final int BUFFER_SIZE = 65536; //blir ikke så stor med mindre d er mye stress på nettet
    String fileInfo = "";
    int transferredFrames = 0;
    String toIP;
    String fromIP;

    public synchronized int transferredFrames(String operation) {

        if (operation.equals("get")) {
            return transferredFrames;
        }
        if (operation.equals("add")) {
            transferredFrames += 1;
        }
        return transferredFrames;
    }

    public FileTransfer(int port, int sockets) { //sockets midlertidig pga klare ikke å skill IPn lokalt
        try {

            ServerSocket serverSocket;
            int counter = 0;
            serverSocket = new ServerSocket(port);

            while ((nrOfSockets * 2) != (toSockets.size() + fromSockets.size())) {
                if (serverSocket.isBound()) {
                    Socket socket = serverSocket.accept();
                    String info=new DataInputStream(socket.getInputStream()).readUTF();
                    if (info.equals("sendcom")) {
                        fromCommunicationSocket = socket;
                        new Thread(new FileInfoSocket(socket)).start();
                        System.out.println("SendCom connected");
                    }
                    if (info.equals("receivecom")) {
                        toCommunicationSocket = socket;
                        System.out.println("ReceiveCom connected");
                    }
                    if (info.equals("sendsocket")) {
                        fromSockets.add(socket);
                        System.out.println("SendSocket "+(fromSockets.size())+" connected");
                    }
                    if (info.equals("receivesocket")) {
                        toSockets.add(socket);
                        System.out.println("ReceiveSocket "+(toSockets.size())+" connected");
                    }

                }
            }

            DataOutputStream dos = new DataOutputStream(fromCommunicationSocket.getOutputStream());
            for (int i = 0; i < nrOfSockets; i++) {
                new Thread(new socketToSocketTransfer(toSockets.get(i), fromSockets.get(i))).start();
            }
            dos.writeUTF("READY");
            System.out.println("Starter transfer!");
        } catch (IOException ex) {
            Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class socketToSocketTransfer implements Runnable {

        Socket toSocket;
        Socket fromSocket;

        public socketToSocketTransfer(Socket toSocket, Socket fromSocket) {
            this.fromSocket = fromSocket;
            this.toSocket = toSocket;
            try {
                toSocket.setPerformancePreferences(0, 1, 3);
                toSocket.setSendBufferSize(10000);
                toSocket.setTcpNoDelay(true);
                fromSocket.setReceiveBufferSize(10000);
                fromSocket.setTcpNoDelay(true);
            } catch (SocketException ex) {
                Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        int totalBitsTransferred = 0;

        @Override
        public void run() {
            try {
                int bitsReadFromStream = 0;
                byte[] buffer = new byte[BUFFER_SIZE];
                while ((bitsReadFromStream = fromSocket.getInputStream().read(buffer)) != -1) {
                    toSocket.getOutputStream().write(buffer, 0, bitsReadFromStream);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class FileInfoSocket implements Runnable {

        Socket socket;

        public FileInfoSocket(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {

                DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                while (toCommunicationSocket == null) {
                    System.out.print("");  //i dont even. må skriv ut nå for at d ska funk.
                }
                System.out.println("sending info to receiver");
                DataOutputStream dos = new DataOutputStream(toCommunicationSocket.getOutputStream());
                fileInfo = dis.readUTF();
                dos.writeUTF(fileInfo);

                int counter = 0;
                for (int i = 0; i < fileInfo.length() - 3; i++) {
                    if (fileInfo.substring(i, i + 3).equalsIgnoreCase("/*/")) {
                        if (counter == 0) {
                            fileInfo = fileInfo.substring(i + 3);
                        }
                        if (counter == 1) {
                            fileSize = Long.valueOf(fileInfo.substring(0, i));
                            fileInfo = fileInfo.substring(i + 3);
                        }
                        if (counter == 2) {
                            frameSize = Integer.valueOf(fileInfo.substring(0, i));

                            fileInfo = fileInfo.substring(i + 3);
                            nrOfSockets = Integer.valueOf(fileInfo);
                        }
                        counter += 1;
                        i = 0;
                    }
                }
                if (fileSize < frameSize) {
                    totalNrOfFrames = 1;
                } else {
                    Double d = Math.floor(fileSize / frameSize);

                    totalNrOfFrames = d.intValue() + 1;
                }
                new DataOutputStream(fromCommunicationSocket.getOutputStream()).writeUTF(new DataInputStream(toCommunicationSocket.getInputStream()).readUTF());
            } catch (IOException ex) {
                Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        new FileTransfer(10823, 4);
    }
}
